#include <iostream>
#include <fstream>

#include <cstring>

//将ptr更新至file_conten中的下一个空格位置
void jump_to_space(const char *file_content,int &ptr){
    while(file_content[ptr]!=' '&&file_content[ptr]!='\0')
        ++ptr;
}

//将ptr更新至file_content中的下一个换行符位置
void jump_to_lineEnd(const char *file_content,int &ptr){
    while(file_content[ptr]!='\n'&&file_content[ptr]!='\0')
        ++ptr;
    while(file_content[ptr]==' ')
        --ptr;
}

//帮助打印函数
void usage(){
    printf("Usage:\nProgram.exe parameter_file\n");
    printf("Format of Parameter file:\n");
    printf("Each para occupies an entire line,parameter_file should be text file with coding utf-8\n");
    printf("-q/-question: Set which quetion (compulsory) \n");
    printf("-i/-input   : Set input file    (compulsory for all) \n");
    printf("-p/-property: Set property file (compulsory for q1) \n");
    printf("-t/-target  : Set target file   (compulsory for q1&q2) \n");
    printf("-o/-output  : Set output file   (compulsory for q1&q2; default for q3 is finiteGrid.vtk) \n");
    printf("-th/-thread : Set thread number (optional) \n");
    printf("E.g: parameter for q1 | parameter for q2               | parameter for q3        \n");
    printf("     -q 1             | -q 2                           | -q 3                    \n");
    printf("     -i Grid_A.out    | -i Grid_and_data.txt           | -i Grid_E.out           \n");
    printf("     -p A_props.txt   | -t Result_grid_coordinates.txt | -o finiteGrid.vtk       \n");
    printf("     -t Grid_B.out    | -o output.txt                  |                         \n");
    printf("     -o B_props.txt   |                                |                         \n");
    exit(1);
}

//解析参数文件
void para_parse(int argc,char **argv,int &question,vector<char *> &para,int &nthread){
    //参数数量小于2，说明未指定参数文件，报错
    if(argc<2){
        cout<<"Not defined parameter file\n";
        usage();
    }
    //匹配帮助选项
    if(strcmp("-h",argv[1])==0||strcmp("-help",argv[1])==0)
        usage();
    
    //处理传参错误
    if(para.size()!=4){
        cout<<"Function:Para_parse got wrong para";
        exit(1);
    }

    //传参初始化
    for(int i=0;i<4;i++){
        para[i]=nullptr;
    }
    question=0;
    nthread=0;
    char *file_content;
    ifstream fp(argv[1]);
    if(!fp){
        cout<<"Failed to open file "<<argv[1]<<endl;
        exit(1);
    }
    fp.seekg(0,ios::end);
    int flen=fp.tellg();
    fp.seekg(0,ios::beg);

    //读入文件内容
    file_content=new char[flen+5];
    memset(file_content,'\0',sizeof(char)*(flen+5));
    fp.read(file_content,flen);
    fp.close();

    //循环遍历参数文件内容，每一行为一条指令
    int ptr=0;
    int start=0;
    int end=0;
    while(ptr<flen){
        if(file_content[ptr]=='-'){
            ++ptr;
            switch(file_content[ptr]){
                //选择问题
                case 'q':{
                    jump_to_space(file_content,ptr);
                    question=stoi(file_content+ptr);
                    jump_to_lineEnd(file_content,ptr);
                    break;
                }
                //input
                case 'i':{
                    jump_to_space(file_content,ptr);
                    start=ptr+1;
                    jump_to_lineEnd(file_content,ptr);
                    end=ptr;
                    para[0]=new char[end-start+1];
                    memcpy(para[0],file_content+start,(end-start+1)*sizeof(char));
                    para[0][end-start]='\0';
                    break;
                }
                //property
                case 'p':{
                    jump_to_space(file_content,ptr);
                    start=ptr+1;
                    jump_to_lineEnd(file_content,ptr);
                    end=ptr;
                    para[1]=new char[end-start+1];
                    memcpy(para[1],file_content+start,(end-start+1)*sizeof(char));
                    para[1][end-start]='\0';
                    break;
                }
                case 't':{
                    //线程参数
                    if(file_content[ptr+1]=='h'){
                        jump_to_space(file_content,ptr);
                        //设定线程为所有线程数，此处线程数需-1
                        nthread=stoi(file_content+ptr)-1;
                        if(nthread<0){
                            cout<<"Set thread to negative, reset it to 0\n";
                            nthread=0;
                        }
                    } else{
                    //target
                        jump_to_space(file_content,ptr);
                        start=ptr+1;
                        jump_to_lineEnd(file_content,ptr);
                        end=ptr;
                        para[2]=new char[end-start+1];
                        memcpy(para[2],file_content+start,(end-start+1)*sizeof(char));
                        para[2][end-start]='\0';
                    }
                    break;
                }
                //output
                case 'o':{
                    jump_to_space(file_content,ptr);
                    start=ptr+1;
                    jump_to_lineEnd(file_content,ptr);
                    end=ptr;
                    para[3]=new char[end-start+1];
                    memcpy(para[3],file_content+start,(end-start+1)*sizeof(char));
                    para[3][end-start]='\0';
                    break;
                }
            }
        }
        ++ptr;
    }

    //判断对应问题，其必须参数是否正确设置
    if(question==1){
        for(int i=0;i<4;i++){
            if(para[i]==nullptr){
                usage();
            }
        }
    } else if(question==2){
        if(para[0]==nullptr||para[2]==nullptr||para[3]==nullptr){
            usage();
        }
    } else if(question==3){
        if(para[0]==nullptr)
            usage();
    } else {
        cout<<"Choose wrong question, should be 1/2/3\n";
        usage();
    }
}